#include <iostream>
#include <cstdlib>
#include "generator/generator.h"

position operator+(const position& pos, const Direction& dir) {
	switch (dir) {
	case Up :
		return position(pos.first-1, pos.second);
	case Down :
		return position(pos.first+1, pos.second);
	case Left :
		return position(pos.first, pos.second-1);
	case Right :
		return position(pos.first, pos.second+1);
	}
}

Case bridge(Direction dir, BridgeType type) {
	if (dir == Up || dir == Down) {
		if (type == Simple)
			return VertSimpleBridge;
		else
			return VertDoubleBridge;
	}
	else
		if (type == Simple)
			return HorizSimpleBridge;
		else
			return HorizDoubleBridge;
}

char CaseToChar(Case c) {
	switch (c) {
	case Empty :
		return ' ';
	case Island :
		return 'I';
	case VertSimpleBridge :
		return '|';
	case VertDoubleBridge :
		return '$';
	case HorizSimpleBridge :
		return '-';
	case HorizDoubleBridge :
		return '=';
	}
}

Generator::Generator() : size(0), availableIslands() {

}

Case** Generator::generate(unsigned int const size) {
	this->size = size;
	genBoard = new Case*[size];
	for (unsigned int i=0 ; i<size ; i++) {
		genBoard[i] = new Case[size];
	}

	for (unsigned int i=0 ; i<size ; i++) {
		for (unsigned int j=0 ; j<size ; j++) {
			genBoard[i][j] = Empty;
			std::cout << genBoard[i][j];
		}
		std::cout << std::endl;
	}
	std::cout << std::endl;


	int count = 0;
	// generation algorithm
	generateRandomIsland();

	int maxIsland = size*size/3;
	while (count++ < 10000 && availableIslands.size() < maxIsland) {
		position island = selectRandomIsland();
		Direction dir = randomDirection();
		BridgeType type = randomType();
		position next = island+dir;
		if (next.first >= 0 && next.first < size &&
				next.second >= 0 && next.second < size &&
				genBoard[next.first][next.second] == Empty) {
			makeBridge(next, dir, type);
		}
	}

	for (unsigned int i=0 ; i<size ; i++) {
		for (unsigned int j=0 ; j<size ; j++) {
			std::cout << CaseToChar(genBoard[i][j]);
		}
		std::cout << std::endl;
	}
	return 0;
}

position Generator::generateRandomIsland() {
	int x = rand()%size;
	int y = rand()%size;
	position pos(x,y);
	if (canPlaceIslandAt(pos)) {
		genBoard[x][y] = Island;
		availableIslands.push_back(pos);
	}
	return pos;
}

bool Generator::canPlaceIslandAt(const position pos) {
	bool retValue = true;
	if (pos.first > 0)
		retValue &= genBoard[pos.first-1][pos.second] != Island;
	if (pos.first < size-1)
		retValue &= genBoard[pos.first+1][pos.second] != Island;
	if (pos.second > 0)
		retValue &= genBoard[pos.first][pos.second-1] != Island;
	if (pos.second < size-1)
		retValue &= genBoard[pos.first][pos.second+1] != Island;
	return retValue;
}

bool Generator::makeBridge(const position pos, const Direction dir, const BridgeType type) {
	if (! (pos.first >= 0 && pos.first < size &&
			pos.second >= 0 && pos.second < size))
		return false;
	switch(genBoard[pos.first][pos.second]) {
	case Empty :
		if (randomContinue()) {
			genBoard[pos.first][pos.second] = bridge(dir, type);
			if (makeBridge(pos+dir, dir, type))
				return true;
			else {
				genBoard[pos.first][pos.second] = Empty;
				return placeIsland(pos);
			}
		}
		else
			return placeIsland(pos);
		break;
	case Island :
		return true;
		break;
	case VertDoubleBridge :
	case VertSimpleBridge :
	case HorizDoubleBridge :
	case HorizSimpleBridge :
		return placeIsland(pos);
	}
	return false;
}

bool Generator::randomContinue() {
	return rand()%3;
}

Direction Generator::randomDirection() {
	return (Direction)(rand()%4);
}

BridgeType Generator::randomType() {
	return (BridgeType)(rand()%2);
}

bool Generator::placeIsland(const position pos) {
	if (canPlaceIslandAt(pos)) {
		genBoard[pos.first][pos.second] = Island;
		availableIslands.push_back(pos);
		return true;
	}
	return false;
}

position Generator::selectRandomIsland() {
	int index = rand()%(availableIslands.size());
	return availableIslands.at(index);
}



